<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>正射投影</title>
</head>
<body>
  <canvas id="c" width="1900" height="1000"></canvas>
  <script  id="vertex-shader-2d" type="notjs">

  // an attribute will receive data from a buffer
  attribute vec3 a_position;
  attribute vec4 a_color;

  uniform vec3 u_resolution;
  uniform mat4 matrix_projection;
  uniform mat4 matrix_translate;
  // uniform mat4 matrix_rotateX;
  // uniform mat4 matrix_rotateY;
  // uniform mat4 matrix_rotateZ;
  // uniform mat4 matrix_scale;

  // all shaders have a main function
  varying vec4 v_color;

  void main() {
    // gl_Position is a special variable a vertex shader
    vec3 position = (matrix_translate  * vec4(a_position, 1)).xyz;
    // vec3 pro_position = (matrix_projection * vec4(position, 1)).xyz;
    vec3 zeroToOne = position - u_resolution / 2.0;

    // 再把 0->1 转换 0->2
    vec3 zeroToTwo = zeroToOne / u_resolution * 2.0;

    // 把 0->2 转换到 -1->+1 (裁剪空间)
    vec3 clipSpace = zeroToTwo * vec3(1.0,-1.0,-1.0);

    gl_Position = vec4(clipSpace, 1);
    // gl_PointSize = 10.0;
    // v_color = vec4(clipSpace,1.0);
    v_color = a_color;
  }

</script>
<script  id="fragment-shader-2d" type="notjs">

  // fragment shaders don't have a default precision so we need
  // highp：高精度，适合需要高精度的计算。mediump：中等精度，适合一般的计算。lowp：低精度，适合颜色计算。
  precision mediump float;
  // uniform vec4 u_color;
  varying vec4 v_color;
  void main() {
    // gl_FragColor is a special variable a fragment shader
    // is responsible for setting
    gl_FragColor = v_color; // return redish-purple
  }

</script>

<script type="module">
    import { createProgram, drawPoints,createPerspectiveMatrix} from './js/createShader3D.js';
    // Get the strings for our GLSL shaders
    var vertexShaderSource = document.querySelector("#vertex-shader-2d").text;
    var fragmentShaderSource = document.querySelector("#fragment-shader-2d").text;
    const {gl,program} = createProgram('#c',vertexShaderSource,fragmentShaderSource);
    import  * as mat4  from './js/glmaxtrix/mat4.js';
    import * as vec3 from './js/glmaxtrix/vec3.js';

    var positions = [
        // ===== 前面的 E (z=500) =====
        // 横线（顶部）
        0, 0, 500,
        300, 0, 500,
        300, 30, 500,
        0, 0, 500,
        0, 30, 500,
        300, 30, 500,

        // 竖线（左侧）
        0, 0, 500,
        0, 400, 500,
        30, 400, 500,
        0, 0, 500,
        30, 0, 500,
        30, 400, 500,

        // 横线（底部）
        0, 400, 500,
        300, 400, 500,
        0, 370, 500,
        0, 370, 500,
        300, 370, 500,
        300, 400, 500,

        // 中间横线
        0, 185, 500,
        200, 185, 500,
        200, 215, 500,
        0, 215, 500,
        0, 185, 500,
        200, 215, 500,

        // ===== 后面的 E (z=400) =====
        // 横线（顶部）
        0, 0, 400,
        300, 0, 400,
        300, 30, 400,
        0, 0, 400,
        0, 30, 400,
        300, 30, 400,

        // 竖线（左侧）
        0, 0, 400,
        0, 400, 400,
        30, 400, 400,
        0, 0, 400,
        30, 0, 400,
        30, 400, 400,

        // 横线（底部）
        0, 400, 400,
        300, 400, 400,
        0, 370, 400,
        0, 370, 400,
        300, 370, 400,
        300, 400, 400,

        // 中间横线
        0, 185, 400,
        200, 185, 400,
        200, 215, 400,
        0, 215, 400,
        0, 185, 400,
        200, 215, 400,

        // ===== 侧面（连接前后 E）=====
        // 顶部横线侧面
        0, 0, 500,  300, 0, 500,  300, 0, 400,
        0, 0, 500,  300, 0, 400,  0, 0, 400,

        300, 0, 500,  300, 30, 500,  300, 30, 400,
        300, 0, 500,  300, 30, 400,  300, 0, 400,

        0, 0, 500,  0, 30, 500,  0, 30, 400,
        0, 0, 500,  0, 30, 400,  0, 0, 400,

        0, 30, 500,  300, 30, 500,  300, 30, 400,
        0, 30, 500,  300, 30, 400,  0, 30, 400,

        // 左侧竖线侧面
        0, 0, 500,  0, 400, 500,  0, 400, 400,
        0, 0, 500,  0, 400, 400,  0, 0, 400,

        30, 0, 500,  30, 400, 500,  30, 400, 400,
        30, 0, 500,  30, 400, 400,  30, 0, 400,

        0, 0, 500,  30, 0, 500,  30, 0, 400,
        0, 0, 500,  30, 0, 400,  0, 0, 400,

        0, 400, 500,  30, 400, 500,  30, 400, 400,
        0, 400, 500,  30, 400, 400,  0, 400, 400,

        // 底部横线侧面
        0, 370, 500,  300, 370, 500,  300, 370, 400,
        0, 370, 500,  300, 370, 400,  0, 370, 400,

        0, 400, 500,  300, 400, 500,  300, 400, 400,
        0, 400, 500,  300, 400, 400,  0, 400, 400,

        // 中间横线侧面
        0, 185, 500,  200, 185, 500,  200, 185, 400,
        0, 185, 500,  200, 185, 400,  0, 185, 400,

        0, 215, 500,  200, 215, 500,  200, 215, 400,
        0, 215, 500,  200, 215, 400,  0, 215, 400,

        200, 185, 500,  200, 215, 500,  200, 215, 400,
        200, 185, 500,  200, 215, 400,  200, 185, 400,
    ];
    // var positions = [0, 0, 200, 0, 200, 10];
    var colorData = [
        200,  70, 120,
        200,  70, 120,
        200,  70, 120,
        200,  70, 120,
        200,  70, 120,
        200,  70, 120,

        // top rung front
        200,  70, 120,
        200,  70, 120,
        200,  70, 120,
        200,  70, 120,
        200,  70, 120,
        200,  70, 120,

        // middle rung front
        200,  70, 120,
        200,  70, 120,
        200,  70, 120,
        200,  70, 120,
        200,  70, 120,
        200,  70, 120,

        // left column back
        80, 70, 200,
        80, 70, 200,
        80, 70, 200,
        80, 70, 200,
        80, 70, 200,
        80, 70, 200,

        // top rung back
        80, 70, 200,
        80, 70, 200,
        80, 70, 200,
        80, 70, 200,
        80, 70, 200,
        80, 70, 200,

        // middle rung back
        80, 70, 200,
        80, 70, 200,
        80, 70, 200,
        80, 70, 200,
        80, 70, 200,
        80, 70, 200,

        // top
        70, 200, 210,
        70, 200, 210,
        70, 200, 210,
        70, 200, 210,
        70, 200, 210,
        70, 200, 210,

        // top rung right
        200, 200, 70,
        200, 200, 70,
        200, 200, 70,
        200, 200, 70,
        200, 200, 70,
        200, 200, 70,

        // under top rung
        210, 100, 70,
        210, 100, 70,
        210, 100, 70,
        210, 100, 70,
        210, 100, 70,
        210, 100, 70,

        // between top rung and middle
        210, 160, 70,
        210, 160, 70,
        210, 160, 70,
        210, 160, 70,
        210, 160, 70,
        210, 160, 70,

        // top of middle rung
        70, 180, 210,
        70, 180, 210,
        70, 180, 210,
        70, 180, 210,
        70, 180, 210,
        70, 180, 210,

        // right of middle rung
        100, 70, 210,
        100, 70, 210,
        100, 70, 210,
        100, 70, 210,
        100, 70, 210,
        100, 70, 210,

        // bottom of middle rung.
        76, 210, 100,
        76, 210, 100,
        76, 210, 100,
        76, 210, 100,
        76, 210, 100,
        76, 210, 100,

        // right of bottom
        140, 210, 80,
        140, 210, 80,
        140, 210, 80,
        140, 210, 80,
        140, 210, 80,
        140, 210, 80,

        // bottom
        90, 130, 110,
        90, 130, 110,
        90, 130, 110,
        90, 130, 110,
        90, 130, 110,
        90, 130, 110,

        // left side
        160, 160, 220,
        160, 160, 220,
        160, 160, 220,
        160, 160, 220,
        160, 160, 220,
        160, 160, 220];

    function animateTranslate(duration,distance) {
        let start = Date.now();
        function step() {
            console.log('run step;')
            let timePassed = Date.now() - start;
            let progress = timePassed / duration;
            if (progress <= 1) {
                linearTransformation(distance*progress);
                window.requestAnimationFrame(step);
            } else {
                return;
            }
        }
        
        window.requestAnimationFrame(step);
    }

    var m4 = {
           //平移矩阵
           translation: function(tx, ty, tz) {
               return new Float32Array([
                    1, 0, 0, 0,
                    0, 1, 0, 0,
                    0, 0, 1, 0,
                    tx, ty, tz,1,
               ]);
           },
            //旋转矩阵
            xRotation: function(angleInRadians) {
                var c = Math.cos(angleInRadians);
                var s = Math.sin(angleInRadians);

                return [
                    1, 0, 0, 0,
                    0, c, s, 0,
                    0, -s, c, 0,
                    0, 0, 0, 1,
                ];
            },

            yRotation: function(angleInRadians) {
                var c = Math.cos(angleInRadians);
                var s = Math.sin(angleInRadians);

                return [
                    c, 0, -s, 0,
                    0, 1, 0, 0,
                    s, 0, c, 0,
                    0, 0, 0, 1,
                ];
            },

            zRotation: function(angleInRadians) {
                var c = Math.cos(angleInRadians);
                var s = Math.sin(angleInRadians);

                return [
                    c, s, 0, 0,
                    -s, c, 0, 0,
                    0, 0, 1, 0,
                    0, 0, 0, 1,
                ];
            },
            //缩放矩阵
           scaling: function(sx, sy, sz) {
               return new Float32Array([
                sx, 0, 0, 0,
                0, sy, 0, 0,
                0, 0, sz, 0,
                0, 0, 0, 1,
               ]);
           },
       };


    var rotateTranslate = gl.getUniformLocation(program, "matrix_translate");

    // 注意矩阵变换要遵循，先平移后缩放再旋转的原则。
    // 初始化矩阵
    const modelMatrix = mat4.create();
    const transLateVector = vec3.fromValues(550,250,0);
    mat4.translate(modelMatrix, modelMatrix, transLateVector);
    // 1. 缩放（先应用）
    mat4.scale(modelMatrix, modelMatrix, [0.5, 0.5, 1]);
    const rotateMarix = mat4.clone(modelMatrix);
    // 2. 旋转（后应用，顺序通常是 X → Y → Z）
    mat4.rotateX(rotateMarix, rotateMarix, 2*Math.PI);
    mat4.rotateY(rotateMarix, rotateMarix, 2*Math.PI);
    mat4.rotateZ(rotateMarix, rotateMarix, 0);

    gl.uniformMatrix4fv(rotateTranslate, false, rotateMarix);

    // three is a question about how the color convert to the color buffer;
    var projection = gl.getUniformLocation(program, "matrix_projection");
    var projectionMatrix = createPerspectiveMatrix(65, 1,0.1, 1000);
    gl.uniformMatrix4fv(projection, false, projectionMatrix);


    var colorBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array(colorData), gl.STATIC_DRAW);
    var colorLocation = gl.getAttribLocation(program, "a_color");
    gl.enableVertexAttribArray(colorLocation);
    var size = 3;                 // 3 components per iteration
    var type = gl.UNSIGNED_BYTE;  // the data is 8bit unsigned values
    var normalize = true;         // normalize the data (convert from 0-255 to 0-1)
    var stride = 0;               // 0 = move forward size * sizeof(type) each iteration to get the next position
    var offset = 0;               // start at the beginning of the buffer
    gl.vertexAttribPointer(
        colorLocation, size, type, normalize, stride, offset);

    // gl.enable(gl.CULL_FACE); //设置正反三角形绘制。

    gl.enable(gl.DEPTH_TEST);

    drawPoints(gl.TRIANGLES,positions,3,126);   

    function linearTransformation(rotata){
        const rotateMarix = mat4.clone(modelMatrix);
        mat4.rotateX(rotateMarix, rotateMarix, rotata);
        mat4.rotateY(rotateMarix, rotateMarix, rotata);
        mat4.rotateZ(rotateMarix, rotateMarix, rotata);
        gl.uniformMatrix4fv(rotateTranslate, false, rotateMarix);

        // var scaleUniform = gl.getUniformLocation(program, "matrix_scale");
        // gl.uniformMatrix4fv(scaleUniform, false, m4.scaling(0.5,0.5,0.5));
        gl.clearColor(0.0, 0.0, 0.0, 1.0);
        // Clear the color buffer with specified clear color
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

        gl.drawArrays(gl.TRIANGLES, 0, 126);
    }
    
    animateTranslate(6000,1.9*Math.PI);

</script>
</body>
</html>